# -*- coding: utf-8 -*-
# 如果你的程序（包括注释）中包含中文，请加上上面这一行，用于指明编码（utf-8）。
# #号开头的行都是注释。

# 如何编辑本程序：
#     用任何文本编辑器均可编辑。

# 如何运行本程序：
#     在终端中，运行：python p801_numpy.py
#
# 依赖模块：
#     numpy  (pip install numpy)
#
# numpy的主页：https://numpy.org/

import numpy as np

'''
Python自带的array模块只支持一维数组。
numpy.array支持多维数组（所以又称为ndarray）。
数组中的元素必须是同一类型。

numpy的数组操作远比Python的list要快得多，
比如在 ipython 环境下运行：
import numpy as np
my_arr = np.arange(1000000)
my_list = list(range(1000000))
%time for _ in range(10): my_arr2 = my_arr * 2 # 结果是毫秒级
%time for _ in range(10): my_list2 = [x*2 for x in my_list] # 结果是秒级

'''

#################### 数组的定义：

# 创建一维数组：
a = np.array([2,3,4])

# 创建二维数组，并指定元素类型（复数）：
b = np.array([ [1,2], [3,4] ], dtype=complex)

'''
a.shape
a.ndim
a.dtype
a.itemsize
a.size
'''

# 创建一个所有元素都是0的二维数组：
np.zeros((3,4))  # 注意维数必须以元组的形式提供（括号不可省略）。

# 创建一个所有元素都是1的三维数组：
np.ones((2,3,4), dtype=np.int16)  # 默认类型是float64

# 创建一个单位矩阵（I）
np.eye(4)  # 4x4的单位矩阵。

# np.arange返回一个array（Python自带的range返回列表）。
np.arange(10, 30, 5)
np.arange(0, 2, 0.3)

x = np.linspace(0, 2*np.pi, 100) # 把0到2*pi进行100等分。
f = np.sin(x)

# reshape函数将数组按照指定的维重新组织：
c = np.arange(24).reshape(2,3,4)


#################### 数组的操作：
# 矢量化（vectorization）：用数组无需for循环就可实现批量操作。

a = np.array([-1, 1, 3, 5])
b = np.arange(4)
a = a.reshape(2,2)
b = b.reshape(2,2)


# 两个数组之间的elementwise运算，两个数组必须具备同样的形状。
c = a - b
d = a * b
a > b

# 数组与标量之间的运算也是elementwise的。
b ** 2
10 * np.sin(a)
a < 3

# 转置（T是ndarray的一个属性）
b.T

a.sum()
a.max()
a.min()
a.sum(axis=0)
a.min(axis=1)

# 通用函数：
np.exp(b)
np.sqrt(b)
np.dot(a,b)  # same as a.dot(b) 或 a @ b


# 以下操作有悖于矢量化的理念，一般很少用到：
for row in b:
    print(row)
    
for element in b.flat:
    print(element)


#################### 索引：

a = np.arange(20)**2
a_slice = a[2:5]  # a_slice包含三个元素。
a_slice[:] = 10  # 将a_slice的所有元素改成10；a的内容也发生了变化。
# 注意：切片（slicing）不创建新数组，只是提供原数组的一个视图。因此
#       改变a_slice元素的值也会改变a，如果不想这样，应该用：
#       a_slice = a[2:5].copy()

b = a.reshape(4,5)
b[0:3, 1]  # 前三行，第二列
b[1]  # 第二行，所有列。或者：b[1,...]
b[1] = 0  # 把第二行的所有元素都赋成0。

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)  # 假设每一行对应names里的一个名字。
data[names == 'Bob']  # 选取Bob对应的行，返回新数组。
data[(names == 'Bob') | (names == 'Will')]  
# 注意：names == 'Bob' 结果是一个布尔数组。对布尔数组不能用and、or，只能用&、|

# 将所有负数改成0：
data[data < 0] = 0

# Fancy indexing:

data = np.empty((8,4))
for i in range(8):
    data[i] = i
print(data)
print(data[[4,3,0,7]])  # 选取给定的行并按给定的顺序排列，返回新数组。













